<?php
###########################################################################
#  Copyright (C) 2006-2007 Glyphix, Inc. <briz@glyphix.com>               #
#                                                                         #
#  Permission is hereby granted, free of charge, to any person obtaining  #
#  a copy of this software and associated documentation files (the        #
#  "Software"), to deal in the Software without restriction, including    #
#  without limitation the rights to use, copy, modify, merge, publish,    #
#  distribute, sublicense, and/or sell copies of the Software, and to     #
#  permit persons to whom the Software is furnished to do so, subject to  #
#  the following conditions:                                              #
#                                                                         #
#  The above copyright notice and this permission notice shall be         #
#  included in all copies or substantial portions of the Software.        #
#                                                                         #
#  Except as contained in this notice, the name(s) of the above           #
#  copyright holders shall not be used in advertising or otherwise to     #
#  promote the sale, use or other dealings in this Software without       #
#  prior written authorization.                                           #
#                                                                         #
#  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        #
#  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     #
#  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. #
#  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR      #
#  OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,  #
#  ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR  #
#  OTHER DEALINGS IN THE SOFTWARE.                                        #
###########################################################################

/**
 * GX
 *
 * Contains reusable functions, abstracted from the GXPage Engine.
 * @author		Brad Brizendine <briz@glyphix.com>
 * @link		http://www.glyphix.com/
 * @license		http://opensource.org/licenses/bsd-license.php BSD License
 * @version		1.0
 * @package		GXPage
 * @subpackage	Helpers
 * @copyright	Copyright 2006 - 2007, Glyphix, Inc.
 * @uses		GXClass
 */

class GX extends GXClass {

	// Object var to ensure only one instance of this object
    private static $instance = NULL;
	// Method to call to instantiate this class
	public static function getInstance( $className = __CLASS__ ){
		if( !isset(self::$instance) ){
			self::$instance = new $className();
		}
		return self::$instance;
	}

	// cache to build unique list of emails
	private $unique;

	function __construct(){
		return parent::__construct();
	}

	private static function __destroy(){
		unset(self::$instance);
	}

	public function showSiteTree( $parentID = null ){
		return $this->GXPage->SiteConfig->getAuthorizedTree();
	}

	public function getFormData( $pageid = null, $actionid = null ){
		if( !$pageid ){
			trigger_error( 'Missing pageid', E_USER_ERROR );
			return false;
		}
		$item = $this->GXPage->SiteConfig->loadItem($pageid,$actionid);
		$filename = $item->getConfig()->exec->xpath('File',0)->nodeValue;
		// generate the filepath from the FS settings
		$filepath = $this->GXPage->Layout->FS->Pages .$filename;
		// generate the list of fields contained in the file
		$x = new GXDOM( 'FormData', null, array('File'=>$filepath) );
		// return a GXDOM object
		return new GXDOM($this->GXPage->xsl($x,'Embed.xsl'));
	}

	/*
	 * getXPath
	 *
	 * Loads the specified page and returns the results of the supplied xpath.
	 * If there's no 'lang' specification in the xpath, it adds one.
	 *
	 * @page String the name of the file (NOT a full path)
	 * @xpath String the xpath to run on the file
	 * @returns Mixed SimpleXMLElement object or false on failure
	 */
	public function getXPath( $page = null, $xpath = null ){
		if( !$page || !$xpath ){
			trigger_error( 'Missing file or xpath', E_USER_ERROR );
			return false;
		}

		// verify the file exists
		$path = $this->GXPage->Layout->FS->Pages .$page;
		if( !$this->GXPage->validatePath($path) ){
			trigger_error( $path .' cannot be found', E_USER_ERROR );
			return false;
		}

		// run the xpath and return the first result
		$page = new GXDOM($path);
		// add lang() test if it's not already in the xpath
		$xpath = (strpos($xpath,'lang')) ? $xpath : $xpath .'[ lang(\'' .$this->GXPage->Params->getLanguage() .'\') ]';
		// run the xpath and return the first result
		if( !($r = $page->exec->xpath($xpath,0)) ){
			trigger_error( 'Specified xpath returned no results', E_USER_WARNING );
			return false;
		}

		return $r;
	}

	public function sendMessage( $txt = null, $route = null, $params = null ){
		if( !$route['To'] ){
			trigger_error( 'Missing destination email (to)', E_USER_ERROR );
			return false;
		}

		// make sure everything's in the route arg
		if( !isset($route['Subject']) ){
			$route['Subject'] = 'Message from ' .$_SERVER['HTTP_HOST'];
		}

		$msg = $txt;
		// if txt is an array, create a simple table for it
		if( is_array($txt) ){
			$msg = '<table border="1" width="100%">' ."\n";
			foreach( $txt as $key => $val ){
				$msg .= "<tr>\n";
				$msg .= "<td>" .$key ."</td><td>" .$val ."</td>\n";
				$msg .= "</tr>\n";
			}
			$msg .= "</table>\n";
		}

		// get rid of doctype, if we have a string and if doctype is the first line
		if( is_string($txt) && strpos($txt,'<!DOCTYPE') === 0 ){
			$parts = preg_split( '/<!DOCTYPE.*?>/', $msg );
			if( count($parts) > 1 ){
				$msg = $parts[1];
			}
		}

		// derive the From address
		$from = isset($route['From']) ? $this->getValidEmail($route['From']) : 'noreply';
		// default headers
		$headers['MIME-Version']		= '1.0';
		// use utf-8 ... gxpage uses utf-8 throughout, and if utf-8 characters are used (trademarks, registered, etc.), iso-8859-1 encoding will screw them up
		$headers['Charset']				= '"utf-8"';
		$headers['Content-type']		= 'text/html; charset=' .trim($headers['Charset'],'"');
		$headers['From']				= 'noreply';
		$headers['Sender']				= $from;
		$headers['X-Mailer']			= 'http://gxpage.googlecode.com/';

		// Generate a unique key for this message, and use it to store info in this object,
		// in case this method is called more than once during a single run.
		$msgKey = md5(serialize($txt));
		$this->unique[$msgKey] = array();
		$to = @implode( ',', $this->filterUnique(explode(',',$route['To']), ($msgKey .'-to')) );
		//$headers['To']					= $to;
		$cc = isset($route['CC']) ? @implode( ',', $this->filterUnique($route['CC'], ($msgKey .'-cc')) ) : null;
		$bcc = isset($route['BCC']) ? @implode( ',', $this->filterUnique($route['BCC'], ($msgKey .'-bcc')) ) : null;
		if( strlen($cc) ){
			$headers['Cc']				= $cc;
		}
		if( strlen($bcc) ){
			$headers['Bcc']				= $bcc;
		}

		// attempt to force sendmail to change the "from" address
		if( $from != 'noreply' ){
			$headers['From']			= $from;
			$headers['Reply-To']		= $from;
			$headers['Return-Path']		= $from;
			//ini_set( 'sendmail_from', $from );
		}

		// generate the header
		// www.php.net/mail states header lines should be terminated with \r\n, but gmail can't parse them unless they're just \n
		$head = null;
		foreach( $headers as $key => $val ){
			$head .= $key .': ' .$val ."\n";
		}

		if( !mail( $to, $route['Subject'], $msg, $head, $params ) ){
			trigger_error( 'There was an error sending your message.' .$to .'::' .print_r($head,true) .print_r($msg,true), E_USER_NOTICE );
			return false;
		}
		trigger_error( 'Sent an email to ' .$to .' with subject ' .$route['Subject'], E_USER_WARNING );
		return true;
	}

	private function filterUnique( $list = null, $key = null ){
		if( !$list || !$key ){
			trigger_error( 'Missing list or key', E_USER_WARNING );
			return false;
		}
		$return = null;
		if( is_array($list) ){
			for( $i = 0; $i < count($list); $i++ ){
				$clean = $this->getValidEmail( $list[$i] );
				$this->unique[$key][$clean] = true;
			}
		}else{
			$clean = $this->getValidEmail($list);
			$this->unique[$key][$clean] = true;
		}
		return array_keys($this->unique[$key]);
	}

	private function getValidEmail( $email = null ){
		$matches = null;
		if( !preg_match( "/\w[-._\w]*\w@\w[-._\w]*\w\.\w{2,3}/", $email, $matches ) ){
			trigger_error( 'Email [' .$email .'] is not a valid email address', E_USER_WARNING );
			return false;
		}
		return $matches[0];
	}

}
